﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace MKAdminCore.ToolKit.Middleware
{
    public class RequestLoggerMiddleware
    {
        private readonly RequestDelegate _next;//下一个中间件
        private readonly ILogger _iLogger;

        public RequestLoggerMiddleware(RequestDelegate next, ILogger<RequestLoggerMiddleware> iLogger)
        {
            this._next = next ?? throw new ArgumentNullException(nameof(next));

            this._iLogger = iLogger ?? throw new ArgumentNullException(nameof(iLogger));
        }

        public async Task Invoke(HttpContext context)
        {
            //非ajax请求或上传文件接口不记录(上传文件接口如果记录会异常,后续查找问题)
            if (!IsAjax(context.Request) || "/home/uploadfile" == context.Request.Path)
            {
                await _next(context);
                return;
            }
            context.Request.EnableBuffering();
            Stopwatch _stopwatch = new Stopwatch();
            _stopwatch.Start();
            _iLogger.LogDebug($"开始处理请求: " + context.Request.Path);

            var api = new ApiRequestInputViewModel();
            api.HttpType = context.Request.Method;
            api.Query = context.Request.QueryString.Value;
            api.RequestUrl = context.Request.Path;
            api.RequestHost = context.Request.Host.Value;
            api.IpAddress = "";

            var reqOrigin = context.Request.Body;
            var resOrigin = context.Response.Body;
            try
            {
                var userAgent = context.Request.Headers["User-Agent"];
                var token = context.Request.Headers["Token"];

                if (userAgent.Count > 0)
                {
                    api.UserAgent = userAgent[0];
                }
                if (token.Count > 0)
                {
                    api.Token = token[0];
                }
                using (var newReq = new MemoryStream())
                {
                    //替换request流
                    context.Request.Body = newReq;
                    using (var newRes = new MemoryStream())
                    {
                        //替换response流
                        context.Response.Body = newRes;
                        using (var reader = new StreamReader(reqOrigin))
                        {
                            //读取原始请求流的内容
                            api.Body = reader.ReadToEnd();
                        }
                        using (var writer = new StreamWriter(newReq))
                        {
                            writer.Write(api.Body);
                            writer.Flush();
                            newReq.Position = 0;
                            await _next(context);
                        }

                        using (var reader = new StreamReader(newRes))
                        {
                            newRes.Position = 0;
                            api.ResponseBody = reader.ReadToEnd();
                        }
                        using (var writer = new StreamWriter(resOrigin))
                        {
                            writer.Write(api.ResponseBody);
                        }
                    }
                }
            }
            finally
            {
                //context.Request
                context.Request.Body = reqOrigin;
                context.Response.Body = resOrigin;
            }

            // 响应完成时存入缓存
            context.Response.OnCompleted(() =>
            {
                _stopwatch.Stop();
                api.ElapsedTime = _stopwatch.ElapsedMilliseconds;

                //大于2s则邮件通知
                if (api.ElapsedTime > 2000)
                {
                    //todo:
                }
                //写入日志
                _iLogger.LogDebug($"{JsonConvert.SerializeObject(api)}");

                return Task.CompletedTask;
            });
        }

        public bool IsAjax(HttpRequest req)
        {
            bool result = false;

            var xreq = req.Headers.ContainsKey("x-requested-with");
            if (xreq)
            {
                result = req.Headers["x-requested-with"] == "XMLHttpRequest";
            }

            return result;
        }
    }

    public class ApiRequestInputViewModel
    {
        /// <summary>
        /// 请求耗时：毫秒
        /// </summary>
        public long ElapsedTime { get; set; }

        /// <summary>
        /// 请求类型：GET/POST
        /// </summary>
        public string HttpType { get; set; }

        /// <summary>
        /// 请求主机头
        /// </summary>
        public string RequestHost { get; set; }

        /// <summary>
        /// 请求路径
        /// </summary>
        public string RequestUrl { get; set; }

        /// <summary>
        /// 请求参数字符串
        /// </summary>
        public string Query { get; set; }

        /// <summary>
        /// 请求报文，POST专用
        /// </summary>
        public string Body { get; set; }

        /// <summary>
        /// 响应内容
        /// </summary>
        public string ResponseBody { get; set; }

        /// <summary>
        /// 请求IP地址
        /// </summary>
        public string IpAddress { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string UserAgent { get; set; }

        public string Token { get; set; }

        public ApiRequestInputViewModel()
        {
            this.IpAddress = "";
            this.RequestUrl = "";
            this.HttpType = "";
            this.Query = "";
            this.Body = "";
            this.ResponseBody = "";
            this.ElapsedTime = -1;
            this.UserAgent = "";
            this.Token = "";
        }
    }
}
